package chooongg.http

import android.content.Context
import chooongg.http.HttpUtils.networkIsConnected
import okhttp3.Cache
import okhttp3.CacheControl
import okhttp3.Interceptor
import okhttp3.OkHttpClient
import retrofit2.Converter
import retrofit2.Retrofit
import java.util.concurrent.TimeUnit
import javax.net.ssl.SSLSocketFactory
import javax.net.ssl.X509TrustManager

class HttpManager private constructor(
    private val context: Context,
    private val config: HttpConfig
) {

    companion object {

        private var INSTANCE: HttpManager? = null

        fun initialize(context: Context, baseUrl: String, config: HttpConfig.() -> Unit) {
            INSTANCE = HttpManager(context, HttpConfig(baseUrl).apply { config() })
        }

        fun default(): HttpManager {
            return if (INSTANCE != null) INSTANCE!! else throw RuntimeException("You need to initialize HttpManager!")
        }

        fun getConfig(): HttpConfig {
            return if (INSTANCE?.config == null) {
                throw RuntimeException("You need to initialize HttpManager!")
            } else INSTANCE!!.config
        }

        fun create(context: Context, baseUrl: String, config: HttpConfig.() -> Unit) =
            HttpManager(context, HttpConfig(baseUrl).apply { config() })
    }

    fun <T> getAPI(api: Class<T>): T {
        val builder = Retrofit.Builder().baseUrl(config.baseUrl).client(configOkHttpClient())
        config.converterFactories.forEach { builder.addConverterFactory(it) }
        return builder.build().create(api)
    }
    private var maxStale = 60 * 60 * 4 * 28

    private fun configOkHttpClient(): OkHttpClient {
        val builder = OkHttpClient.Builder()

        val cacheFile = context.cacheDir
        val cache = Cache(cacheFile, config.cacheSize)
        val cacheInterceptor = Interceptor { chain ->
            var request = chain.request()
            if (!networkIsConnected()) {
                val tempCacheControl = CacheControl.Builder()
                    .maxStale(maxStale, TimeUnit.SECONDS)
                    .onlyIfCached()
                    .build()
                request = request.newBuilder()
                    .cacheControl(tempCacheControl)
                    .build()
            }
            chain.proceed(request)
        }
        builder.connectTimeout(config.connectTimeout, TimeUnit.SECONDS)
            .writeTimeout(config.writeTimeout, TimeUnit.SECONDS)
            .readTimeout(config.readTimeout, TimeUnit.SECONDS)
            .retryOnConnectionFailure(true)
            .cache(cache)
            .addInterceptor(cacheInterceptor)
            .addNetworkInterceptor(
                LoggingInterceptor.Builder()
                    .loggable(isDebug())
                    .hideVerticalLine()
                    .request()
                    .response()
                    .build()
            )

        config.interceptors.forEach { builder.addInterceptor(it.value) }
        config.networkInterceptors.forEach { builder.addNetworkInterceptor(it.value) }

        if (config.sslSocketFactory != null && config.trustManager != null) {
            builder.sslSocketFactory(config.sslSocketFactory!!, config.trustManager!!)
        }

        return builder.build()
    }


    class HttpConfig(val baseUrl: String) {

        companion object {
            // TimeUnit.SECONDS
            internal const val DEFAULT_TIMEOUT_CONNECT = 30L
            internal const val DEFAULT_TIMEOUT_WRITE = 30L
            internal const val DEFAULT_TIMEOUT_READ = 30L

            internal const val DEFAULT_HTTP_CACHE_SIZE = 10L * 1048576//默认缓存大小10MB
        }

        internal var connectTimeout = DEFAULT_TIMEOUT_CONNECT
        internal var writeTimeout = DEFAULT_TIMEOUT_WRITE
        internal var readTimeout = DEFAULT_TIMEOUT_READ
        internal var cacheSize = DEFAULT_HTTP_CACHE_SIZE
        internal val interceptors = HashMap<String, Interceptor>()
        internal val networkInterceptors = HashMap<String, Interceptor>()

        internal var sslSocketFactory: SSLSocketFactory? = null
        internal var trustManager: X509TrustManager? = null

        internal val converterFactories = ArrayList<Converter.Factory>()

        fun connectTimeout(connectTimeout: Long) = apply {
            this.connectTimeout = connectTimeout
        }

        fun writeTimeout(writeTimeout: Long) = apply {
            this.writeTimeout = writeTimeout
        }

        fun readTimeout(readTimeout: Long) = apply {
            this.readTimeout = readTimeout
        }

        fun cacheSize(cacheSize: Long) = apply {
            this.cacheSize = cacheSize
        }

        fun addInterceptor(name: String, interceptor: Interceptor) = apply {
            interceptors[name] = interceptor
        }

        fun addNetworkInterceptor(name: String, interceptor: Interceptor) = apply {
            networkInterceptors[name] = interceptor
        }

        fun sslSocketFactory(sslSocketFactory: SSLSocketFactory) = apply {
            this.sslSocketFactory = sslSocketFactory
        }

        fun trustManager(trustManager: X509TrustManager) = apply {
            this.trustManager = trustManager
        }

        fun addConverterFactory(converterFactory: Converter.Factory) = apply {
            if (converterFactories.contains(converterFactory)) return this
            converterFactories.add(converterFactory)
        }
    }
}